package cn.tedu.aop.demo;
//定义一个切面,用于在计算机类的方法中动态插入逻辑
//在Spring中一个切面类需要:
//1.添加@Component注解  首先必须被Spring管理
//2:添加@Aspect注解   用于标识它是一个切面类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class SystoutAspect {
    /**
     * @Before注解用于标注该方法是在实际方法调用前切入并执行
     * 该注解中要传入一个参数，用于定义切入点(目标方法,target)，就是实际调用的方法签名
     *
     * 切入点描述:
     * execution(方法签名)
     *
     * 方法签名格式示例:
     * public int cn.tedu.aop.demo.CalculatorImpl.add(..)
     * 修饰符 返回值类型 类完全限定名.方法名(参数列表)
     * 其中参数列表通常可以使用".."标识任意参数
     *
     * 方法名可以使用"*",标识该类的任意方法:
     * public int cn.tedu.aop.demo.CalculatorImpl.*(..)
     */
//    @Before("execution(public int cn.tedu.aop.demo.CalculatorImpl.add(int,int))")
//    @Before("execution(public int cn.tedu.aop.demo.CalculatorImpl.add(int,double))")//切入点描述有误则无效
//    @Before("execution(public double cn.tedu.aop.demo.CalculatorImpl.add(double,double))")
//    @Before("execution(public java.lang.String cn.tedu.aop.demo.CalculatorImpl.add(java.lang.String,java.lang.String))")//如果参数或返回值为引用类型，也要使用完全限定名:包名.类名
//    @Before("execution(public int cn.tedu.aop.demo.CalculatorImpl.add(..))")//参数类型任意，但是仍然只有int add(int,int)被切入，原因是其他add方法返回值类型也不同
//    @Before("execution(public * cn.tedu.aop.demo.CalculatorImpl.add(..))")//返回值类型可以使用"*"表示任意类型的返回值均可
//    @Before("execution(public * cn.tedu.aop.demo.CalculatorImpl.*(..))")
//    public void before(JoinPoint point){
////        System.out.println("切面类被方法调用用前被调用");
////        通过切入点对象获取实际调用的方法调用的方法所属的对象
////        Object target = point.getTarget();//CalculatorImpl实例
////        System.out.println("target:"+target);
////        //获取该类的名字?
////        Class cls = target.getClass();
////        //通过类对象获取该类的完全限定名
////        System.out.println(cls.getName());
////        //仅获取类名
////        System.out.println(cls.getSimpleName());
////        //通过切入点获取实际调用的方法(方法签名)
////        Signature signature = point.getSignature();
////        String methodName = signature.getName();
////        System.out.println("方法名:"+methodName);
////        System.out.println("方法信息:"+signature);
////
////        //通过切入点获取实参列表
////        Object[] args = point.getArgs();
////        System.out.println("实参:"+ Arrays.toString(args));
//
//        String className = point.getTarget().getClass().getSimpleName();
//        String methodName = point.getSignature().getName();
//        System.out.println(className+"."+methodName+"():开始执行");
//
//    }
//    @AfterReturning(value = "execution(public * cn.tedu.aop.demo.CalculatorImpl.*(..))",returning = "returnValue")
//    public void afterReturning(JoinPoint point,Object returnValue){
//        String className = point.getTarget().getClass().getSimpleName();
//        String methodName = point.getSignature().getName();
//        System.out.println(className+"."+methodName+"():执行完毕,返回值是"+returnValue);
//    }
//
//    /**
//     * @After注解是在目标方法执行完毕后调用的
//     * 无论该方法执行过程中是否出现异常,最后都会执行
//     *
//     * 在方法正常返回时,
//     * @param point
//     */
//
//    @After("execution(public * cn.tedu.aop.demo.CalculatorImpl.*(..))")
//    public void after(JoinPoint point){
//        String className = point.getTarget().getClass().getSimpleName();
//        String methodName = point.getSignature().getName();
//        System.out.println(className+"."+methodName+"():执行完毕");
//    }
//
//    @AfterThrowing(value = "execution(public * cn.tedu.aop.demo.CalculatorImpl.*(..))",throwing = "e")
//    public void afterThrowing(JoinPoint point,Exception e){
//        String className = point.getTarget().getClass().getSimpleName();
//        String methodName = point.getSignature().getName();
//        System.out.println(className+"."+methodName+"():抛出异常了,异常是:"+e.getMessage());
//    }
    @Around("execution(public * cn.tedu.aop.demo.CalculatorImpl.*(..))")
    public Object around(ProceedingJoinPoint point){
        String className = point.getTarget().getClass().getSimpleName();
        String methodName = point.getSignature().getName();
        Object[] args = point.getArgs();
        try{
            //这里就是@Before的操作
            System.out.println(className+"."+methodName+"():开始调用方法...");

            //调用实际方法并接收返回值
            Object returnValue = point.proceed();

            //这里就是@AfterReturning的操作
            System.out.println(className+"."+methodName+"():方法执行完毕,返回值为:"+returnValue);
            return  returnValue;
        }catch (Throwable e){
            //这里就是@AfterThrowing的操作
            System.out.println(className+"."+methodName+"():方法抛出异常了,异常是:"+e.getMessage());
            throw new RuntimeException(e);
        }finally {
            //这里就是@After的操作
            System.out.println(className+"."+methodName+"():方法执行完毕了");
        }
    }
}
